package ua.tach.shortl.logic;

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

import ua.tach.shortl.Bank;
import ua.tach.shortl.RenderCounter;

import com.badlogic.gdx.Application;
import com.badlogic.gdx.Files.FileType;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;

public class Country {
	// size of playing country (always square)
	public static final int VIRTUAL_COUNTRY_SIZE = 9;

	// Square field with 8x8 crossing points and 1-wide border around
	public static final float COUNTRY_SIZE = 10.0f;
	public static final float COUNTRY_STEP = 1.0f; // Step between points

	// Length of year
	public static final int TICKS_IN_YEAR = 200; // one year is 20 sec , 200 ticks
	// for city building
	public static final int CITY_TICKS = 2;

	// Game sounds
	public static Sound cashSound ;
	public static Sound railSound ;
	public static Sound trainSound ;
	public static Music intro;

	public static final Vector3[] CITY_COLORS = {
		new Vector3(0, 1, 1),
		new Vector3(1, 0, 1),
		new Vector3(0, 1, 0),
		new Vector3(0, 0, 1),
		new Vector3(1, 0, 0),
		new Vector3(1, 1, 0),
		new Vector3(1, 1, 1) // for crazy train and drezina
	};

	private static float accum = 0; // ticks counter

	public static FlyingRail flyingRail;
	public static GameLevel myGameLevel = new GameLevel(1);
	public static Random randomGenerator = new Random();
	public final static Vector2 vect = new Vector2();
	public final static Vector3 scr = new Vector3();
	public static Link[] links = new Link[VIRTUAL_COUNTRY_SIZE*VIRTUAL_COUNTRY_SIZE];

	private static ArrayList<Rail> railroad = new ArrayList<Rail>();
	private static ArrayList<CityPlace> cities = new ArrayList<CityPlace>();
	private static int numCities;
	private static CopyOnWriteArrayList<Train> trains = new CopyOnWriteArrayList<Train>();
	private static CopyOnWriteArrayList<SwitchPlace> switches = new CopyOnWriteArrayList<SwitchPlace>();
	public static CopyOnWriteArrayList<CrashPlace> crashes = new CopyOnWriteArrayList<CrashPlace>();
	public static CopyOnWriteArrayList<Tree> trees = new CopyOnWriteArrayList<Tree>();

	// Counters - will use Object for rendering
	public static int[] Counters = { 1800, 0, 1 };
	private static int yearTicks = 0;
	private static int cityTicks = 0;
	private static RenderCounter cnYear;
	private static RenderCounter cnTrain;
	public static Bank bank;

	// Game control
	public static boolean gamePause;
	public static boolean enableSound;
	public static int menuWait;

	// for debug
//	private static CrashPlace crash = new CrashPlace(new Vector2(5,5));

	public Country(Application app) {
		cashSound = app.getAudio().newSound(app.getFiles().getFileHandle("data/cash.ogg", FileType.Internal));
		railSound = app.getAudio().newSound(app.getFiles().getFileHandle("data/rail.ogg", FileType.Internal));
		trainSound = app.getAudio().newSound(app.getFiles().getFileHandle("data/train.ogg", FileType.Internal));
	}

	public static void update(float delta) {
		// 10 ticks per sec
		accum += delta;
		while(accum > 1.0f / 10.0f) {
			tick();
			accum -= 1.0f / 10.0f;
		}
	}

	public static void init (RenderCounter y, RenderCounter t, Bank m) {
		cnYear = y;
		cnTrain = t;
		bank = m;

		flyingRail = new FlyingRail();
		Point i = new Point(0,0);
		for(i.x=VIRTUAL_COUNTRY_SIZE-1; i.x>=0; --i.x)
			for(i.y=VIRTUAL_COUNTRY_SIZE-1; i.y>=0; --i.y) {
				if(i.isCityCoordinate() ) {
					//System.out.println("City " + i);
					links[i.getIndex()] = new CityPlace(i);
					cities.add((CityPlace)links[i.getIndex()]);
				} else if(i.isUnavail())
					links[i.getIndex()] = new DeadLink(i);
				else
					links[i.getIndex()] = new Link(i);
			}
		// place trees
		generateForest();

		// Generate first city
		numCities = 0;
		CityPlace cc = addCity();
		for (int i1=16; i1>0 ; --i1)
			cc.tick();
	}

	public static void playMusic(boolean pl) {
		if (intro != null) {
			if (pl) {
				if (enableSound) intro.play();
			} else {
				intro.stop();
			}
		}
	}

	public static void clickHandler(int x, int y) {
		if (switches.size() == 0) return;
		scr.set(x, y, 0);
		SwitchPlace s = switches.get(0);
		for(SwitchPlace swp : switches) {
			if(swp.scr.dst2(scr)<s.scr.dst2(scr)) {
				s = swp;
			}
		}
		if (s.scr.dst(scr) < 50)
			s.sw.click();
//		else
//			System.out.println("Dst= "+s.scr.dst(scr));
	}

	// Convert screen coordinates into country vector
	public static void setvect(Vector3 v) {
		vect.set(9.4f-v.y*0.72f-v.x*0.38f, 5.6f-v.y*0.72f+v.x*0.38f);
	}

	public static void render(GL10 gl) {

		gl.glEnable(GL10.GL_BLEND);
		for(Tree t : trees) t.render(gl);
		for(Rail rr : railroad) rr.render(gl);
		gl.glColor4f(1.f, 1.f, 1.f, 1.f);
		gl.glDisable(GL10.GL_BLEND);

		for(Train tr : trains) tr.render(gl);
		for(Link ll : links) ll.render(gl);

		for( CrashPlace c : crashes)
			c.render(gl);

		flyingRail.render(gl);

//		for(SwitchPlace swp : switches) {
//			Renderer.toLoad[21].tx.bind();
//			gl.glPushMatrix();
//			gl.glTranslatef(swp.pos.x, 0, swp.pos.y);
//			Renderer.toLoad[21].m.render(GL10.GL_TRIANGLES);
//			gl.glPopMatrix();
//		}

//		Renderer.toLoad[21].tx.bind();
//		gl.glPushMatrix();
//		gl.glTranslatef(vect.x, 0, vect.y);
//		Renderer.toLoad[21].m.render(GL10.GL_TRIANGLES);
//		gl.glPopMatrix();

	}

	public static void addRail(Rail r, Point last, int d1, int d2) {
		railroad.add(r);
		links[r.shift.getIndex()].addRail(d1, r, true);
		links[r.shift.getIndex(last)].addRail(d2, r, false);
	}
	public static void addRail(Rail r) {
		railroad.add(r);
	}

	public static void addSwitch( Switch sw) {
		System.out.println("Sw to array: "+ sw);
		SwitchPlace swp = new SwitchPlace(sw);
		switches.add(swp);
	}
	public static void removeSwitch( Switch sw) {
		for(SwitchPlace swp : switches) {
			if(swp.sw == sw) {
				switches.remove(swp);
				break;
			}
		}
	}
	public static void chgSwitch( Switch sw) {
		for(SwitchPlace swp : switches) {
			if(swp.sw == sw) {
				swp.change();
				break;
			}
		}
	}

	public static void addTrain(Train tr) {
		trains.add(tr);
		tr.waiting = false;
	}
	public static void removeTrain(Train tr) {
		trains.remove(tr);
		for(SwitchPlace swp : switches) 
			swp.sw.unlock(tr);
		tr.dispose();
	}
	public static void startTrain() {
//		System.out.println("num cities "+ numCities);
		if (numCities < 2) return;
		while (true) {
			CityPlace ccc = cities.get(randomGenerator.nextInt(6));
			if (ccc.station == Rail.NULL) continue;
			ccc.startTrain();
			return;
		}
	}

	public static void removeTree(Tree t) {
		trees.remove(t);
	}
	public static boolean checkTree(Vector2 p) {
		for(Tree t : trees)
			if(t.here(p))
				return true;
		return false;
	}
	public static int cutTree(Vector2 p) {
		int drova = 0;
		for(Tree t : trees)
			if(t.here(p)) {
				++drova;
				trees.remove(t);
			}
		return drova;
	}
	public static void generateForest() {
		int forests = myGameLevel.GetForests();
		Vector2 ff = new Vector2();
		Vector3 c = new Vector3();
		while (--forests>0) {
			ff.set(randomGenerator.nextInt(9), randomGenerator.nextInt(9));
			int treeCount = myGameLevel.GetForestTrees();
			while (treeCount > 0) {
				ff.add(randomGenerator.nextFloat()*0.7f-0.35f,randomGenerator.nextFloat()*0.7f-0.35f);
				if (!checkTree(ff)) {
					trees.add(new Tree(ff, randomGenerator.nextInt(2), randomGenerator.nextFloat() * 270,
							c.set(0.5f+randomGenerator.nextFloat()/3, 0.8f+randomGenerator.nextFloat()/5, 0.5f+randomGenerator.nextFloat()/4)));
					--treeCount;
				}
			}
		}
	}

	public static Vector3 getTrainColor( Vector3 c) {
		if(numCities<2) return c;
		while (true) {
			int rnd = randomGenerator.nextInt(numCities);
			if(c.equals(CITY_COLORS[rnd])) continue;
			return CITY_COLORS[rnd];
		}
	}

	public static int getWaitingTrain(int city) {
		for (CityPlace c : cities) {
			if (c.color != city) continue;
			if(c.station == Rail.NULL) break;
			if(c.waitingTrain == Train.NULL)
				return 1;
			return 0;
		}
		return 2;
	}

	public static CityPlace addCity() {
		CityPlace cc;
		if(numCities>5) return null;
		while (true) {
			int rnd = randomGenerator.nextInt(6);
//			System.out.println("Start City at "+ rnd + " color "+ numCities);
			if(cities.get(rnd).station == Rail.NULL) {
				cc = cities.get(rnd);
				break;
			}
		}
		cc.startCity(numCities++);
		return cc;
	}

	public static void tick() {
		if (gamePause) return;

		for (CityPlace cp : cities) {
			if(cp.railBusy>0) --cp.railBusy;
		}

		if ( ++yearTicks > TICKS_IN_YEAR ) {
			++Counters[0];
			yearTicks = 0;

			// Check if city year (each 37 after 1801: 1838 1875 1912 1949-last)
			if ((Counters[0]-1801)%37 == 0)
				addCity();
		}

		cnYear.tick();
		cnTrain.tick();
		if (!bank.btick()) {
			// End game
			gamePause = true;
		}

		for( CrashPlace c : crashes)
			c.tick();

		if ( ++cityTicks > CITY_TICKS ) {
			cityTicks = 0;
			for(CityPlace cc : cities) cc.tick(); // check for new house
			// check for new city:
			// is (year)?
		}

		flyingRail.tick();
		for(Rail rr : railroad) rr.tick();
		for(Train tr : trains) {
			// Check collision - get first wagon and check other trains
			if (tr.tick()) {
				removeTrain(tr);
			}
		}
		for(CityPlace c2 : cities) c2.trainTick();
	}
}
